#include "StdAfx.h"
#include "AnimationGraphDialog_2.h"
#include "IViewPane.h"
#include "AnimationGraph_2.h"
#include "IslandDetection_2.h"
#include "SpeedReport_2.h"
#include "ICryAnimation.h"
#include "TransitionReport_2.h"
#include "CharacterEditor\CharPanel_Animation.h"
#include "CharacterEditor\ModelViewportCE.h"
#include "PropertiesPanel.h"
#include "AnimationGraph2_Modifier.h"
#include "AnimationGraph2_Randomizer.h"

#pragma warning(disable:4355) // warning C4355: 'this' : used in base member initializer list

#define ANIMATIONGRAPH_DIALOGFRAME_CLASSNAME "AnimationGraphDialog2"
//#define ANIMATIONGRAPH_FILE_FILTER "Animation Graph 2.0 Files (*.ag2xml)|*.ag2xml; |Animation Graph 1.0 Files (*.xml)|*.xml"
#define ANIMATIONGRAPH_FILE_FILTER "Animation Graph Files (*.xml)|*.xml"
#define ANIMATIONGRAPH_FILE_INITIALDIR "Animations/Graphs"
#define CHARACTER_FILE_FILTER "Character Files (*.cdf)|*.cdf"

enum
{
	IDC_ANIMGRAPH_STATES = 1,
	IDC_ANIMGRAPH_STATEPARAMS,
	IDC_ANIMGRAPH_VIEWS,
	IDC_ANIMGRAPH_INPUTS,
	IDC_ANIMGRAPH_MODIFIERS,
	IDC_ANIMGRAPH_ANIMATIONS
};

enum 
{
	IDW_ANIMGRAPH_STATES_PANE = AFX_IDW_PANE_FIRST + 20,
	IDW_ANIMGRAPH_STATE_EDITOR_PANE,
	IDW_ANIMGRAPH_TEST_PANE,
	IDW_ANIMGRAPH_PREVIEW_PANE,
	IDW_ANIMGRAPH_PREVIEW_OPTIONS_PANE,
	IDW_ANIMGRAPH_STATE_PARAMS_PANE,
	IDW_ANIMGRAPH_STATE_QUERY_PANE,
	IDW_ANIMGRAPH_VIEWS_PANE,
	IDW_ANIMGRAPH_INPUTS_PANE,
	IDW_ANIMGRAPH_ANIMATIONS_PANE,
	IDW_ANIMGRAPH_VIEW_PANE,

	// new animation graph 2.0 panels
	IDW_ANIMGRAPH_MODIFIER_PANE,
	IDW_ANIMGRAPH_DETAILS_PANE,
	ANIMATION_GRAPH_PANE_COUNT = (IDW_ANIMGRAPH_DETAILS_PANE - IDW_ANIMGRAPH_STATES_PANE + 1)
};

enum
{
	IDC_REMOVE_FROM_VIEW = 32760,
	IDC_REMOVE_DISCONNECT,
	IDC_DELETE_COMPLETELY
};

namespace AnimationGraphDialogHelpers2
{
	const char* GetDefaultCharacterName()
	{
		const char* szEditModelFallback = "objects/characters/sdk_player/sdk_player.cdf";

		ICVar* charEditModelCVar = GetIEditor()->GetSystem()->GetIConsole()->GetCVar( "ca_CharEditModel" );
		if ( !charEditModelCVar )
			return szEditModelFallback;

		const char* szCharEditModel = charEditModelCVar->GetString();

		if ( szCharEditModel && szCharEditModel[0] ) 
			return szCharEditModel;
		else
			return szEditModelFallback;
	}
}

class CAnimationGraphViewClass2 : public TRefCountBase<IViewPaneClass>
{
	//////////////////////////////////////////////////////////////////////////
	// IClassDesc
	//////////////////////////////////////////////////////////////////////////
	virtual ESystemClassID SystemClassID() { return ESYSTEM_CLASS_VIEWPANE; };
	virtual REFGUID ClassID()
	{
		// {196C52AA-35FD-41E6-B76A-C401903DCC01}
		static const GUID guid = { 0x196c52aa, 0x35fd, 0x41e6, { 0xb7, 0x6a, 0xc4, 0x1, 0x90, 0x3d, 0xcc, 0x1 } };
		return guid;
	}
	virtual const char* ClassName() { return ANIMATION_GRAPH_NAME; };
	virtual const char* Category() { return "Animation"; };
	//////////////////////////////////////////////////////////////////////////
	virtual CRuntimeClass* GetRuntimeClass() { return RUNTIME_CLASS(CAnimationGraphDialog2); };
	virtual const char* GetPaneTitle() { return _T(ANIMATION_GRAPH_NAME); };
	virtual EDockingDirection GetDockingDirection() { return DOCK_FLOAT; };
	virtual CRect GetPaneRect() { return CRect(200,200,1000,800); };
	virtual bool SinglePane() { return false; };
	virtual bool WantIdleUpdate() { return false; };
};




//////////////////////////////////////////////////////////////////////////
// CAGHyperGraphView2
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CAGHyperGraphView2,CHyperGraphView)

void CAGHyperGraphView2::ShowContextMenu( CPoint point, CHyperNode* pNode )
{
	OnLButtonDown( 0, point );
	OnLButtonUp( 0, point );
	if ( pNode )
	{
		ClientToScreen( &point );

		if (CAnimationGraphDialog2* pDialog = static_cast<CAnimationGraphDialog2*>(GetParent()))
		{
			pDialog->OnContextMenu(this, point);
		}
	}
}

//////////////////////////////////////////////////////////////////////////
// CAnimationGraphDialog2
//////////////////////////////////////////////////////////////////////////

void CAnimationGraphDialog2::RegisterViewClass()
{
	GetIEditor()->GetClassFactory()->RegisterClass( new CAnimationGraphViewClass2 );
	GetIEditor()->GetSettingsManager()->AddToolName("AnimationGraph1_5Layout", "Animation Graph 1_5");
	GetIEditor()->GetSettingsManager()->AddToolVersion(ANIMATION_GRAPH_NAME,ANIMATION_GRAPH_VER);
}

IMPLEMENT_DYNCREATE(CAnimationGraphDialog2, CXTPFrameWnd);

BEGIN_MESSAGE_MAP(CAnimationGraphDialog2, CXTPFrameWnd)
	ON_WM_SIZE()
	ON_WM_SETFOCUS()
	ON_WM_DESTROY()
	ON_WM_CLOSE()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_CONTEXTMENU()
	
	ON_COMMAND( ID_FILE_NEW,OnFileNew )
	ON_COMMAND( ID_FILE_OPEN,OnFileOpen )
	ON_COMMAND( ID_FILE_SAVE,OnFileSave )
	ON_COMMAND( ID_FILE_SAVE_AS,OnFileSaveAs )
	ON_COMMAND( ID_EDIT_DELETE,OnDelete )
	ON_COMMAND( ID_GRAPH_ADDSTATE,OnGraphAddState )
	ON_COMMAND( ID_GRAPH_ADDVIEW,OnGraphAddView )
	ON_COMMAND( ID_GRAPH_ADDINPUT,OnGraphAddInput )
	ON_COMMAND_RANGE( ID_GRAPH_ADDMODIFIER_FIRST, ID_GRAPH_ADDMODIFIER_LAST, OnGraphAddModifier )

	ON_COMMAND( ID_GRAPH_CREATEANIMATION,OnGraphCreateAnimation )
	ON_COMMAND( ID_GRAPH_TRIAL,OnGraphTrial )
	ON_COMMAND( ID_GRAPH_ISLANDREPORT,OnGraphIslandReport )
	ON_COMMAND( ID_GRAPH_SPEEDREPORT,OnGraphSpeedReport )
	ON_COMMAND( ID_GRAPH_DEADINPUTREPORT,OnGraphDeadInputReport )
	ON_COMMAND( ID_GRAPH_BADCALFILEREPORT,OnGraphBadCALReport )
	ON_COMMAND( ID_GRAPH_TRANSITIONLENGTHREPORT,OnGraphTransitionLengthReport )
	ON_COMMAND( ID_GRAPH_MATCHMOVEMENTTEMPLATESPEEDSTOANIMATIONSPEEDS,OnGraphMatchSpeeds )
	ON_COMMAND( ID_GRAPH_BADNULLNODEREPORT, OnGraphBadNullNodeReport )
	ON_COMMAND( ID_GRAPH_ORPHANNODEREPORT, OnGraphOrphanNodesReport )
	ON_COMMAND( ID_SETTINGS_EDITDEFAULTSETTINGS, OnGraphDefaultSettingsDialog )
	ON_COMMAND( ID_AGVERSION_INFO, OnGraphVersionInfo )

	ON_COMMAND_EX( ID_VIEW_STATES, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_VIEWS, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_DETAILS, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_MODIFIERS, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_STATEQUERY, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_INPUTS, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_PREVIEW, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_PREVIEWOPTIONS, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_STATEEDITOR, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_STATEPARAMS, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_ANIMATIONS, OnViewPane )
	ON_COMMAND_EX( ID_VIEW_VIEW, OnViewPane )

	ON_COMMAND( ID_AGLINK_MAPPINGCHANGED, OnAGLinkMappingChanged )

	ON_COMMAND( ID_TOOLS_CUSTOMIZEKEYBOARD,OnCustomize )
	ON_COMMAND( ID_TOOLS_EXPORT_SHORTCUTS, OnExportShortcuts )
	ON_COMMAND( ID_TOOLS_IMPORT_SHORTCUTS, OnImportShortcuts )

	ON_XTP_EXECUTE( ID_ANIMATION_GRAPH_ICON_SIZE, OnIconSizeChanged )
	ON_UPDATE_COMMAND_UI( ID_ANIMATION_GRAPH_ICON_SIZE, OnUpdateIconSizeUI )
	ON_XTP_EXECUTE( ID_ANIMATION_GRAPH_ICONS, OnDisplayIconsChanged )
	ON_UPDATE_COMMAND_UI( ID_ANIMATION_GRAPH_ICONS, OnUpdateDisplayIconsUI )
	ON_XTP_EXECUTE( ID_ANIMATION_GRAPH_PREVIEW, OnDisplayPreviewChanged )
	ON_UPDATE_COMMAND_UI( ID_ANIMATION_GRAPH_PREVIEW, OnUpdateDisplayPreviewUI )

	ON_NOTIFY( TVN_SELCHANGED, IDC_ANIMGRAPH_STATES, OnStateListSelChanged )
	ON_NOTIFY(NM_CLICK , IDC_ANIMGRAPH_STATES, OnStateListClick)

	ON_NOTIFY( TVN_BEGINDRAG, IDC_ANIMGRAPH_STATES, OnBeginDrag )

	ON_NOTIFY( TVN_SELCHANGED, IDC_ANIMGRAPH_MODIFIERS, OnModifierListSelChanged )
	ON_NOTIFY( TVN_BEGINDRAG, IDC_ANIMGRAPH_MODIFIERS, OnModifierListBeginDrag )

	ON_NOTIFY( TVN_SELCHANGED, IDC_ANIMGRAPH_VIEWS, OnViewListSelChanged )
	ON_NOTIFY(NM_CLICK , IDC_ANIMGRAPH_VIEWS, OnViewListClick)

	ON_NOTIFY( TVN_SELCHANGED, IDC_ANIMGRAPH_INPUTS, OnInputListSelChanged )
	ON_NOTIFY(NM_CLICK , IDC_ANIMGRAPH_INPUTS, OnInputListClick)
	

	//////////////////////////////////////////////////////////////////////////
	// XT Commands.
	ON_MESSAGE(XTPWM_DOCKINGPANE_NOTIFY, OnDockingPaneNotify)
	ON_MESSAGE( XTPWM_TASKPANEL_NOTIFY, OnTaskPanelNotify )
END_MESSAGE_MAP()

CAnimationGraphDialog2::CAnimationGraphDialog2()
	: m_stateListCtrl(this)
	, m_viewListCtrl(this)
	, m_inputListCtrl(this)
	, m_modifierListCtrl(this)
	, m_pDragImage(NULL)
	, m_nBlockSelChanged(0)
	, m_previewDialog(AnimationGraphDialogHelpers2::GetDefaultCharacterName())
	, m_pView(NULL)
	, m_pNodeDetailsPane(NULL)
	, m_hAccelerators(0)
	, m_view(NULL)
{
	SEventLog toolEvent(ANIMATION_GRAPH_NAME,"",ANIMATION_GRAPH_VER);
	GetIEditor()->GetSettingsManager()->RegisterEvent(toolEvent);

	RegisterConsoleVariables();

	//m_enableIcons->Set(true);

	m_iconSizes.push_back(std::make_pair(64, 64));
	m_iconSizes.push_back(std::make_pair(96, 96));
	m_iconSizes.push_back(std::make_pair(128, 128));
	m_iconSizes.push_back(std::make_pair(192, 192));
	m_iconSizes.push_back(std::make_pair(256, 256));
	m_iconSizes.push_back(std::make_pair(512, 512));

	WNDCLASS wndcls;
	HINSTANCE hInst = AfxGetInstanceHandle();
	if (!(::GetClassInfo(hInst, ANIMATIONGRAPH_DIALOGFRAME_CLASSNAME, &wndcls)))
	{
		// otherwise we need to register a new class
		wndcls.style            = 0 /*CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW*/;
		wndcls.lpfnWndProc      = ::DefWindowProc;
		wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
		wndcls.hInstance        = hInst;
		wndcls.hIcon            = NULL;
		wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
		wndcls.hbrBackground    = NULL; // (HBRUSH) (COLOR_3DFACE + 1);
		wndcls.lpszMenuName     = NULL;
		wndcls.lpszClassName    = ANIMATIONGRAPH_DIALOGFRAME_CLASSNAME;
		if (!AfxRegisterClass(&wndcls))
		{
			AfxThrowResourceException();
		}
	}
	CRect rc(0,0,0,0);
	BOOL bRes = Create( WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,rc,AfxGetMainWnd() );
	if (!bRes)
		return;
	ASSERT( bRes );

	OnInitDialog();
}

CAnimationGraphDialog2::~CAnimationGraphDialog2()
{
	m_stateEditor.ClearActiveItem();

	SEventLog toolEvent(ANIMATION_GRAPH_NAME,"",ANIMATION_GRAPH_VER);
	GetIEditor()->GetSettingsManager()->UnregisterEvent(toolEvent);
}

void CAnimationGraphDialog2::OnDestroy()
{
	if (m_pGraph)
	{
		m_pGraph->RemoveListener(this);
		m_pGraph = 0;
	}
	if (m_pViewHypergraph)
	{
		m_pViewHypergraph->RemoveListener(this);
		m_pViewHypergraph = 0;
	}

	CXTPDockingPaneLayout layout( GetDockingPaneManager() );
	GetDockingPaneManager()->GetLayout( &layout );
	layout.Save( _T("AnimationGraph1_5Layout") );

	__super::OnDestroy();
}

BOOL CAnimationGraphDialog2::Create( DWORD dwStyle,const RECT& rect,CWnd* pParentWnd )
{
	BOOL bReturn = __super::Create( ANIMATIONGRAPH_DIALOGFRAME_CLASSNAME,NULL,dwStyle,rect,pParentWnd );

	m_pCAnimationImageManager = new CAnimationImageManager2(this, AnimationGraphDialogHelpers2::GetDefaultCharacterName(), std::make_pair(64, 64));

	return bReturn;
}

void CAnimationGraphDialog2::OnCharacterChanged()
{
	// update the graph and mark it as modified
	if ( m_pGraph )
		m_pGraph->SetCharacterName( m_previewDialog.GetModelViewport()->GetLoadedFileName() );

	// recreate the icons
	m_pCAnimationImageManager->ChangeModelAssetName( m_previewDialog.GetModelViewport()->GetLoadedFileName() );
	
	m_animationListView.Clear();

	if(m_previewDialog.GetModelViewport() && m_previewDialog.GetModelViewport()->GetCharacterAnim())
		m_animationListView.UpdateAnimations( m_previewDialog.GetModelViewport()->GetCharacterAnim()->GetIAnimationSet() );
	
	// invalidate the entire view.
	SetActiveView( m_pView );
}

BOOL CAnimationGraphDialog2::OnInitDialog()
{
	static UINT indicators[] = 
	{
		ID_SEPARATOR,
	};

	if (!m_statusBar.Create(this) ||
		!m_statusBar.SetIndicators(indicators,
		sizeof(indicators)/sizeof(UINT)))
	{
		TRACE0("Failed to create status bar\n");
		return -1;      // fail to create
	}

	try
	{
		//////////////////////////////////////////////////////////////////////////
		// Initialize the command bars
		if (!InitCommandBars())
			return -1;

	}	catch (CResourceException *e)
	{
		e->Delete();
		return -1;
	}

	m_hAccelerators = LoadAccelerators(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDR_HYPERGRAPH));
	ModifyStyleEx( WS_EX_CLIENTEDGE, 0 );

	// Get a pointer to the command bars object.
	CXTPCommandBars* pCommandBars = GetCommandBars();
	if(pCommandBars == NULL)
	{
		TRACE0("Failed to create command bars object.\n");
		return -1;      // fail to create
	}

	CMFCUtils::LoadShortcuts(pCommandBars, IDR_ANIMATIONGRAPH_2, "AnimationGraph");

	m_defaultsDialog.SetAnimationGraph(GetAnimationGraph());

	// Add the menu bar
	CXTPCommandBar* pMenuBar = pCommandBars->SetMenu( _T("Menu Bar"), IDR_ANIMATIONGRAPH_2 );

	ASSERT(pMenuBar);

	pMenuBar->SetFlags(xtpFlagStretched);
	pMenuBar->EnableCustomization(TRUE);
	
	//////////////////////////////////////////////////////////////////////////
	GetDockingPaneManager()->InstallDockingPanes(this);
	GetDockingPaneManager()->HideClient( TRUE );
	GetDockingPaneManager()->SetTheme( CMainFrame::GetDockingPaneTheme() );
	
	GetDockingPaneManager()->SetThemedFloatingFrames(TRUE);
	if (CMainFrame::GetDockingHelpers())
	{
		GetDockingPaneManager()->SetAlphaDockingContext(TRUE);
		GetDockingPaneManager()->SetShowDockingContextStickers(TRUE);
	}	

	// Toolbar
	m_wndToolBar = GetCommandBars()->Add( _T("ToolBar"),xtpBarTop );
	VERIFY(m_wndToolBar->LoadToolBar( IDR_ANIMATION_GRAPH ));

	//////////////////////////////////////////////////////////////////////////
	CRect rc(0,0,890,490);
	CXTPDockingPane* pViewPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_VIEW_PANE,rc,dockBottomOf);
	pViewPane->SetTitle( _T("View") );

	// States
	CRect rectStateListCtrl(0,0,240,360);
	m_stateListCtrl.Create( /*WS_VISIBLE|*/WS_CHILD|WS_TABSTOP|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,rectStateListCtrl,this,IDC_ANIMGRAPH_STATES );
	m_stateListCtrl.ReloadStates();

	CXTPDockingPane* pStatesPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_STATES_PANE,rectStateListCtrl,dockLeftOf, pViewPane );
	pStatesPane->SetTitle( _T("States") );

	// Inputs
	m_inputListCtrl.Create( /*WS_VISIBLE|*/WS_CHILD|WS_TABSTOP|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,rectStateListCtrl,this,IDC_ANIMGRAPH_INPUTS );
	m_inputListCtrl.ReloadInputs();

	CXTPDockingPane* pInputsPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_INPUTS_PANE,rectStateListCtrl,dockTopOf,pStatesPane );
	pInputsPane->SetTitle( _T("Inputs") );
	GetDockingPaneManager()->AttachPane(pInputsPane, pStatesPane);

	// Modifiers
	m_modifierListCtrl.Create( /*WS_VISIBLE|*/WS_CHILD|WS_TABSTOP|WS_CLIPSIBLINGS|WS_CLIPCHILDREN, rectStateListCtrl, this, IDC_ANIMGRAPH_MODIFIERS );
	m_modifierListCtrl.ReloadModifiers();

	CXTPDockingPane* pModifierPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_MODIFIER_PANE, rectStateListCtrl, dockTopOf, pStatesPane );
	pModifierPane->SetTitle( _T("Modifiers") );
	GetDockingPaneManager()->AttachPane(pModifierPane, pStatesPane);
	pStatesPane->Select();

	// Views
	CRect rectViewListCtrl(0,0,240,155);
	m_viewListCtrl.Create( /*WS_VISIBLE|*/WS_CHILD|WS_TABSTOP|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,rectViewListCtrl,this,IDC_ANIMGRAPH_VIEWS );
	m_viewListCtrl.ReloadViews();

	CXTPDockingPane* pViewsPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_VIEWS_PANE,rectViewListCtrl,dockBottomOf,pStatesPane );
	pViewsPane->SetTitle( _T("Views") );

	// Animations
	CRect rectAnimationListCtrl(0,0,240,370);
	CXTPDockingPane* pAnimationsPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_ANIMATIONS_PANE,rectAnimationListCtrl,dockBottomOf, pViewsPane);
	pAnimationsPane->SetTitle( _T("Animations") );

	m_animationListView.Create( IDD_LMG_ANIMATION_LIST_VIEW, this );
	m_animationListView.AddDragDropListener( m_stateEditor.GetAnimNodeDetailsPane()->GetAnimationTab() );
	m_animationListView.SetSelectionChangeListener( this );

	// State Params
	m_stateParamsCtrl.Create( m_stateParamsCtrl.IDD );
	m_stateParamsCtrl.ModifyStyle( 0, WS_VSCROLL );
	m_stateParamsCtrl.ModifyStyleEx( 0, WS_EX_STATICEDGE );
	m_stateParamsCtrl.Init();

	CRect rectStateParamsCtrl( 0, 0, 245, 545);
	CXTPDockingPane* pStateParamsPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_STATE_PARAMS_PANE,rectStateParamsCtrl,dockBottomOf, pViewPane );
	pStateParamsPane->SetTitle( "State Params" );
	pStateParamsPane->Hide();

	// Generic Pane for Node Details
	m_genericNodeDetails.Create( m_genericNodeDetails.IDD );
	CRect rectNodeDetailsCtrl( 0, 0, 245, 545);
	CXTPDockingPane* m_pNodeDetailsPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_DETAILS_PANE, rectNodeDetailsCtrl, dockBottomOf, pViewPane );
	m_pNodeDetailsPane->SetTitle( _T("Node Details") );

	// State Editor
	CXTPDockingPane* pStateEditorPane = m_stateEditor.Init(this, IDW_ANIMGRAPH_STATE_EDITOR_PANE);
	m_stateEditor.GetPanel()->SetOwner(this);

	// Attach all node's details panes here and hide them
	//m_genericNodeDetails.Attach(m_stateEditor.GetAnimNodeDetailsPane()->GetSafeHwnd());
	//m_pNodeDetailsPane->ShowWindow( SW_HIDE );

	// Preview Options
	CRect rectPreviewOptionsCtrl(0,0,220,515);
	CXTPDockingPane* pPreviewOptionsPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_PREVIEW_OPTIONS_PANE,rectPreviewOptionsCtrl,dockRightOf, pStateEditorPane);
	pPreviewOptionsPane->SetTitle( _T("Preview Options") );
	//pPreviewOptionsPane->Hide();
	pPreviewOptionsPane->Close();

	// Preview
	CRect rectPreviewCtrl(0,0,220,515);
	m_previewDialog.Create( CAnimationGraphPreviewDialog2::IDD,this );
	m_previewManager.SetViewport( m_previewDialog.GetModelViewport() );
	m_previewDialog.GetModelViewport()->SetCharacterChangeListener( this );
	CXTPDockingPane* pPreviewPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_PREVIEW_PANE,rectPreviewCtrl,dockTopOf, pStateEditorPane);
	pPreviewPane->SetTitle( _T("Preview") );

	m_rollupCtrl.Create(/*WS_VISIBLE|*/WS_CHILD,CRect(4, 4, 187, 362),this, NULL);
	CharPanel_Animation* pAnimationPanel = new CharPanel_Animation(m_previewDialog.GetModelViewport(), NULL);
	m_previewDialog.GetModelViewport()->SetModelPanelA(pAnimationPanel);
	//m_previewDialog.GetModelViewport()->UpdateAnimationList(); // Xiaomao: don't need to update animation list in animation graph
	/*int animationControlRollupID = */m_rollupCtrl.InsertPage("Character Animation", pAnimationPanel);

	CPropertiesPanel* s_varsPanel;
	s_varsPanel = new CPropertiesPanel(this);
	s_varsPanel->AddVars( m_previewDialog.GetModelViewport()->GetVarObject()->GetVarBlock() );
	/*int propertiesRollupID = */m_rollupCtrl.InsertPage("Debug Options", s_varsPanel);

	// Testing
	m_tester.Init( this );
	CXTPDockingPane* pTestPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_TEST_PANE, rectStateListCtrl, dockRightOf, pViewPane );
	pTestPane->SetTitle( _T("Testing") );
	pTestPane->Close();
//	pTestPane->Hide();

	// State Query
	m_stateQuery.Init( this );
	CXTPDockingPane* pStateQueryPane = GetDockingPaneManager()->CreatePane( IDW_ANIMGRAPH_STATE_QUERY_PANE, rectStateListCtrl, dockRightOf, pViewPane );
	pStateQueryPane->SetTitle( _T("State Query") );
	//pStateQueryPane->Hide();
	pStateQueryPane->Close();

	UpdateTitle();

	// Create the resolution combo box.
	{
		CXTPControl *pCtrl = m_wndToolBar->GetControls()->FindControl(xtpControlButton, ID_ANIMATION_GRAPH_ICON_SIZE, TRUE, FALSE);
		if (pCtrl)
		{
			int nIndex = pCtrl->GetIndex();
			CXTPControlComboBox *pCombo = (CXTPControlComboBox*)m_wndToolBar->GetControls()->SetControlType(nIndex,xtpControlComboBox);
			pCombo->SetWidth(80);

			int index = 0;
			for (IconSizeList::iterator itSize = m_iconSizes.begin(); itSize != m_iconSizes.end(); ++itSize)
			{
				int width = (*itSize).first;
				int height = (*itSize).second;
				string text;
				text.Format("%d x %d", width, height);
				pCombo->InsertString(index, text.c_str());
				++index;
			}
			pCombo->SetCurSel(m_displayedIconSize->GetIVal());
			m_pCAnimationImageManager->SetImageSize(m_iconSizes[m_displayedIconSize->GetIVal()]);
		}

		ReadDisplayedIconSize();
	}

	// Create the enable/disable icons button.
	{
		CXTPControl *pCtrl = m_wndToolBar->GetControls()->FindControl(xtpControlButton, ID_ANIMATION_GRAPH_ICONS, TRUE, FALSE);
		if (pCtrl)
		{
			int nIndex = pCtrl->GetIndex();
			CXTPControlButton *pPopup = (CXTPControlButton*)m_wndToolBar->GetControls()->SetControlType(nIndex,xtpControlButton);
			pPopup->SetCaption("Display Icons");
			pPopup->SetStyle(xtpButtonCaption);
		}
	}

	// Create the enable/disable preview button.
	{
		CXTPControl *pCtrl = m_wndToolBar->GetControls()->FindControl(xtpControlButton, ID_ANIMATION_GRAPH_PREVIEW, TRUE, FALSE);
		if (pCtrl)
		{
			int nIndex = pCtrl->GetIndex();
			CXTPControlButton *pPopup = (CXTPControlButton*)m_wndToolBar->GetControls()->SetControlType(nIndex,xtpControlButton);
			pPopup->SetCaption("Preview Animations");
			pPopup->SetStyle(xtpButtonCaption);
			m_previewManager.EnablePreview( m_preview->GetIVal() );
		}
	}

	CXTPDockingPaneLayout layout( GetDockingPaneManager() );
	
	if (layout.Load( _T("AnimationGraph1_5Layout")))
	{
		const int numPanes = layout.GetPaneList().GetCount();
		if (numPanes >= ANIMATION_GRAPH_PANE_COUNT)
		{
			GetDockingPaneManager()->SetLayout(&layout);
		}
	}

	if (pViewPane = GetDockingPaneManager()->FindPane(IDW_ANIMGRAPH_VIEW_PANE))
	{
		m_view = DYNAMIC_DOWNCAST(CAGHyperGraphView2, pViewPane->AttachView(this, RUNTIME_CLASS(CAGHyperGraphView2)));
	}
	
	return TRUE;
}

void CAnimationGraphDialog2::OnFileNew()
{
	CAnimationGraph2Ptr pGraph = new CAnimationGraph2(m_pCAnimationImageManager, this);
	pGraph->CreateMinimumGraph();
	SetGraph( pGraph );
}

void CAnimationGraphDialog2::OnFileOpen()
{
	CAnimationGraph2Ptr pGraph = new CAnimationGraph2(m_pCAnimationImageManager, this);
	CString filename;
	CString initialDir(Path::Make(Path::GetGameFolder(), ANIMATIONGRAPH_FILE_INITIALDIR));
	if (CFileUtil::SelectSingleFile(EFILE_TYPE_ANY, filename, ANIMATIONGRAPH_FILE_FILTER, initialDir))
	{
		CWaitCursor wait;
		if (pGraph->Load( filename ))
			SetGraph( pGraph );
	}
}

bool CAnimationGraphDialog2::SetGraph(const char* graphName)
{
	CAnimationGraph2Ptr pGraph = new CAnimationGraph2(m_pCAnimationImageManager, this);
	if (pGraph->Load( graphName ))
	{
		SetGraph( pGraph );
		return true;
	}
	return false;
}

void CAnimationGraphDialog2::OnFileSave()
{
	if (!m_pGraph)
		return;

	m_view->ClearSelection();
	m_stateEditor.ClearActiveItem();

	if (m_pGraph->GetFilename().IsEmpty())
		OnFileSaveAs();
	else
	{
		CWaitCursor wait;
		m_pGraph->Save();

		m_stateQuery.RunUnitTests( true, false );
		m_stateQuery.Reload( false );
	}
}

void CAnimationGraphDialog2::OnFileSaveAs()
{
	CString filename = m_pGraph->GetFilename();
	CString dir = Path::GetPath(filename);
	if (CFileUtil::SelectSaveFile( ANIMATIONGRAPH_FILE_FILTER, "xml", dir, filename ))
	{
		m_view->ClearSelection();
		m_stateEditor.ClearActiveItem();

		CWaitCursor wait;
		m_pGraph->SetFilename( filename );
		m_pGraph->Save();

		m_stateQuery.Reload( false );
	}
}


void CAnimationGraphDialog2::OnDelete()
{
	const int commandGroupId = 100;
	const int deleteCommandId = commandGroupId + eSEE_Delete2;
	m_stateEditor.OnCommand( deleteCommandId );
}


void CAnimationGraphDialog2::SetGraph( CAnimationGraph2Ptr pGraph )
{
	m_pView = NULL;
	m_vStates.clear();

	m_view->SetGraph( NULL );
	m_pViewHypergraph = NULL;
	m_stateEditor.ClearActiveItem();
	if (m_pGraph)
		m_pGraph->RemoveListener(this);
	m_pGraph = pGraph;
	if (m_pGraph)
		m_pGraph->AddListener(this);
	m_defaultsDialog.SetAnimationGraph(pGraph);
	m_stateListCtrl.ReloadStates();
	m_viewListCtrl.ReloadViews();
	m_inputListCtrl.ReloadInputs();
	m_modifierListCtrl.ReloadModifiers();
	m_tester.Reload();
	m_stateQuery.Reload( false );
	m_previewDialog.SetCharacter( pGraph->GetCharacterName().IsEmpty() ? AnimationGraphDialogHelpers2::GetDefaultCharacterName() : pGraph->GetCharacterName() );
	pGraph->ShowIcons(m_enableIcons->GetIVal());

	// Attach the Modifier Manager here
	//m_pNodeDetailsPane->Attach(m_pGraph->GetModifierManager());

	UpdateTitle();

	UpdateGraphMenu();
}

void CAnimationGraphDialog2::UpdateTitle()
{
	CString titleFormatter;
	if (m_pGraph)
	{
		if (m_pGraph->IsModified())
			titleFormatter += "modified ";
		titleFormatter += m_pGraph->GetFilename();
	}
	else
	{
		titleFormatter += "No file open.";
	}
	m_statusBar.SetPaneText(0, titleFormatter );
}

CAnimationGraph2Ptr CAnimationGraphDialog2::GetAnimationGraph()
{
	return m_pGraph;
}

bool CAnimationGraphDialog2::ResetParameterization()
{
	if ( !m_stateEditor.IsParameterized() )
		return true;

	if ( AfxMessageBox("The selected item has custom parameterized data which will be lost by this action! \n\nProceed?", MB_YESNO|MB_DEFBUTTON2) == IDNO )
		return false;

	m_stateEditor.ResetParameterization();
	return true;
}

void CAnimationGraphDialog2::OnStateListSelChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
	if (m_nBlockSelChanged)
		return;

	CWaitCursor wait;

	*pResult = TRUE;
	if (!m_pGraph)
		return;
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	HTREEITEM treeitem = pNMTreeView->itemNew.hItem;
	if (treeitem != NULL)
	{
		m_inputListCtrl.SelectItem(NULL);
		m_modifierListCtrl.SelectItem(NULL);
	}
	CString item = m_stateListCtrl.GetItemText(treeitem);
	m_previewManager.SetState(CAGState2Ptr(0));
	m_vStates.clear();
	m_view->ClearSelection();
	SetActiveState( m_pGraph->FindState(item) );
}

void CAnimationGraphDialog2::OnViewListSelChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
	CWaitCursor wait;

	*pResult = TRUE;
	if (!m_pGraph)
		return;
	if (m_nBlockSelChanged)
		return;
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	HTREEITEM treeitem = pNMTreeView->itemNew.hItem;
	if (treeitem != NULL)
	{
		m_stateListCtrl.SelectItem(NULL);
		m_inputListCtrl.SelectItem(NULL);
	}
	CString item = m_viewListCtrl.GetItemText(treeitem);
	m_previewManager.SetState(CAGState2Ptr(0));
	m_vStates.clear();
	SetActiveView( m_pGraph->FindView(item) );
	m_stateEditor.EditPropertiesOf( m_pGraph->FindView(item) );
}

void CAnimationGraphDialog2::OnInputListSelChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
	CWaitCursor wait;

	*pResult = TRUE;
	if (!m_pGraph)
		return;
	if (m_nBlockSelChanged)
		return;
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	HTREEITEM treeitem = pNMTreeView->itemNew.hItem;
	if (treeitem != NULL)
	{
		m_stateListCtrl.SelectItem(NULL);
		m_modifierListCtrl.SelectItem(NULL);
	}
	CString item = m_inputListCtrl.GetItemText(treeitem);
	m_previewManager.SetState(CAGState2Ptr(0));
	m_vStates.clear();
	m_view->ClearSelection();
	m_stateEditor.EditPropertiesOf( m_pGraph->FindInput(item) );
}

void CAnimationGraphDialog2::OnGraphModified()
{
	UpdateTitle();
	m_stateQuery.Reload( true );
}

void CAnimationGraphDialog2::SetActiveState( CAGState2Ptr pState )
{
	m_vStates.clear();
	if ( pState )
	{
		m_vStates.push_back( pState );
		SelectState(pState->GetName());
		m_stateEditor.EditPropertiesOf( pState );
		m_previewManager.SetState( pState );
		if ( m_pView )
		{
			CHyperNode* pNode = m_pView->GetNodeForState( pState );
			if ( pNode && !pNode->IsSelected() )
				m_view->ShowAndSelectNode( pNode, true );
		}
		m_pGraph->GetModifierManager()->SetSelectedModifier(NULL);
	}
	else
	{
		SelectState("");
		if (m_stateEditor.GetActiveItem())
		{
			m_stateEditor.ClearActiveItem();
		}
		m_previewManager.SetState( CAGState2Ptr(0) );
	}
}

void CAnimationGraphDialog2::SetActiveStates( std::vector< CAGState2Ptr > vStates )
{
	if ( vStates.empty() )
		SetActiveState( NULL );
	else if ( vStates.size() == 1 )
		SetActiveState( vStates[0] );
	else
	{
		m_stateEditor.EditPropertiesOf( vStates );
		m_previewManager.SetState( CAGState2Ptr(0) );
		if ( m_pView )
		{
			std::vector< CAGState2Ptr >::iterator it, itEnd = vStates.end();
			for ( it = vStates.begin(); it != itEnd; ++it )
			{
				CAGState2* pState = *it;
				CHyperNode* pNode = m_pView->GetNodeForState( pState );
				if ( pNode && !pNode->IsSelected() )
					m_view->ShowAndSelectNode( pNode, true );
			}
		}
	}
}

void CAnimationGraphDialog2::SetActiveView( CAGView2Ptr pView )
{
	if (m_pViewHypergraph)
	{
		m_pViewHypergraph->RemoveListener(this);
		m_pViewHypergraph = NULL;
		m_view->SetGraph(NULL);
	}
	m_pView = pView;
	if (m_pView)
	{
		m_pViewHypergraph = pView->GetHyperGraph();
		m_pViewHypergraph->AddListener(this);
		m_view->SetGraph( m_pViewHypergraph );
	}
}

void CAnimationGraphDialog2::OnStateEvent( EAGStateEvent2 evt, CAGState2Ptr pState )
{
	switch (evt)
	{
	case eAGSE_ChangeName2:
		++m_nBlockSelChanged;
		m_stateListCtrl.ReloadStates();
		SelectState(pState->GetName());
		--m_nBlockSelChanged;
		SetActiveView( m_pView );
		break;
	case eAGSE_Cloned2:
	case eAGSE_Removed2:
		++m_nBlockSelChanged;
		m_stateListCtrl.ReloadStates();
		m_tester.Reload();
		m_stateQuery.Reload( true );
		--m_nBlockSelChanged;

		SetActiveView( m_pView );

		if (evt != eAGSE_Removed2)
		{
			SetActiveState( pState );
			m_stateListCtrl.SelectItemByName( pState->GetName() );
		}
		else
		{
			HTREEITEM firstItem = m_stateListCtrl.GetFirstVisibleItem();
			m_stateListCtrl.SelectItem(firstItem);
		}

		break;
	case eAGSE_ChangeUseTemplate2:
		m_stateQuery.Reload( true );
		break;
	case eAGSE_ChangeParent2:
		m_stateQuery.Reload( true );
		break;
	case eAGSE_ChangeIconSnapshotTime2:
		{
			m_pCAnimationImageManager->InvalidateImage(pState);

			class InvalidateNodeTreeRecursive
			{
			public:
				static void Perform(CHyperGraph* pViewHypergraph, CHyperNode* pNode)
				{
					if (pNode)
					{
						pViewHypergraph->InvalidateNode(pNode);
						pNode->Invalidate(true);
						IHyperGraphEnumerator* pEnum = pNode->GetChildrenEnumerator();
						if (pEnum)
						{
							for (IHyperNode* pChild = pEnum->GetFirst(); pChild; pChild = pEnum->GetNext())
								Perform(pViewHypergraph, static_cast<CHyperNode*>(pChild));
							pEnum->Release();
						}
					}
				}
			};

			InvalidateNodeTreeRecursive::Perform(m_pViewHypergraph, m_pView->GetNodeForState(pState));
		}
		break;
	}
}

void CAnimationGraphDialog2::OnViewEvent( EAGViewEvent2 evt, CAGView2Ptr pView )
{
	switch (evt)
	{
	case eAGVE_ChangeName2:
		++m_nBlockSelChanged;
		m_viewListCtrl.ReloadViews();
		m_tester.Reload();
		SetActiveView( m_pView );
		m_viewListCtrl.SelectItemByName( m_pView->GetName() );
		--m_nBlockSelChanged;
		break;
	case eAGVE_Removed2:
		++m_nBlockSelChanged;
		m_stateEditor.ClearActiveItem();
		m_viewListCtrl.ReloadViews();

		HTREEITEM firstVisibleItem = m_viewListCtrl.GetFirstVisibleItem();
		m_viewListCtrl.SelectItem(firstVisibleItem);
	
		CString newViewName = m_viewListCtrl.GetItemText(firstVisibleItem);
		CAGView2Ptr newView = m_pGraph->FindView(newViewName);

		m_stateEditor.EditPropertiesOf(newView);
		SetActiveView(newView);
		--m_nBlockSelChanged;
		break;
	}
}

void CAnimationGraphDialog2::OnInputEvent( EAGInputEvent2 evt, CAGInput2Ptr pInput )
{
	switch (evt)
	{
	case eAGIE_ChangeName2:
	case eAGIE_ChangeType2:
	case eAGIE_Removed:
		++m_nBlockSelChanged;
		m_inputListCtrl.ReloadInputs();
		m_tester.Reload();
		m_stateQuery.Reload( true );
		SetActiveView( m_pView );
		m_inputListCtrl.SelectItemByName( pInput->GetName() );
		--m_nBlockSelChanged;
		break;
	}
}

LRESULT CAnimationGraphDialog2::OnTaskPanelNotify(WPARAM wParam, LPARAM lParam)
{
	switch(wParam) 
	{
	case XTP_TPN_CLICK:
		{
			CXTPTaskPanelGroupItem* pItem = (CXTPTaskPanelGroupItem*)lParam;
			UINT nCmdID = pItem->GetID();
			if (nCmdID < 60)
				m_tester.OnCommand(nCmdID);
			else if (nCmdID < 100)
				m_stateQuery.OnCommand(nCmdID);
			else
				m_stateEditor.OnCommand(nCmdID);
		}
		break;

	case XTP_TPN_RCLICK:
		break;
	}

	return 0;
}

void CAnimationGraphDialog2::OnHyperGraphEvent( IHyperNode * pNode, EHyperGraphEvent event )
{
	CAGNodeBase2* pBaseNode = (CAGNodeBase2*)pNode;
	if (!pBaseNode)
		return;

	if (pBaseNode->GetAGNodeType() == AG_NODE_MODIFIER)
	{
		OnModifierNodeEvent(pBaseNode, event);
	}
	else
	{
		OnStateNodeEvent(event);
	}


}

void CAnimationGraphDialog2::OnLinkEdit( CHyperEdge * pEdge )
{
	CAGLink2Ptr pLink = ((CAGEdge2*)pEdge)->pLink;
	m_stateEditor.EditPropertiesOf( pLink );
}

void CAnimationGraphDialog2::OnBeginDrag( NMHDR* pNMHDR, LRESULT* pResult )
{
	NM_TREEVIEW * pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	*pResult = TRUE;
	bool doDrag = false;

	HTREEITEM hItem = pNMTreeView->itemNew.hItem;
	m_dragNodeClass = m_stateListCtrl.GetItemText(hItem);
	doDrag = !!m_pView && m_pView->CanAddState( m_pGraph->FindState(m_dragNodeClass) );

	if (doDrag)
	{
		m_pDragImage = m_stateListCtrl.CreateDragImage( hItem );
		if (m_pDragImage)
		{
			m_pDragImage->BeginDrag(0, CPoint(-10, -10));
			CRect rc;
			GetWindowRect(rc);
			CPoint p = pNMTreeView->ptDrag;
			ClientToScreen( &p );
			p.x -= rc.left;
			p.y -= rc.top;
			m_pDragImage->DragEnter( this, p );
			SetCapture();

			*pResult = FALSE;
		}
	}
}

void CAnimationGraphDialog2::OnMouseMove(UINT nFlags, CPoint point)
{
	if (m_pDragImage)
	{
		CRect rc;
		GetWindowRect(rc);
		CPoint p = point;
		ClientToScreen(&p);
		p.x -= rc.left;
		p.y -= rc.top;
		m_pDragImage->DragMove(p);
		return;
	}
	__super::OnMouseMove(nFlags, point);
}

void CAnimationGraphDialog2::OnLButtonUp(UINT nFlags, CPoint point)
{
	if (m_pDragImage)
	{
		CPoint p;
		GetCursorPos( &p );

		m_pDragImage->DragLeave( this );
		m_pDragImage->EndDrag();
		delete m_pDragImage;
		m_pDragImage = 0;
		ReleaseCapture();

		CWnd *wnd = CWnd::WindowFromPoint( p );
		if (wnd == m_view)
		{
			m_view->ScreenToClient(&p);

			m_view->CreateNode( m_dragNodeClass, p );
			m_dragNodeClass.Empty();
		}

		return;
	}
	__super::OnLButtonUp(nFlags, point);
}

void CAnimationGraphDialog2::OnContextMenu( CWnd* pWnd, CPoint pos )
{
	if ( pos.x == -1 && pos.y == -1 )
	{
		__super::OnContextMenu( pWnd, pos );
		return;
	}

	CWnd* wnd = WindowFromPoint( pos );
	if ( !wnd || wnd != &m_stateListCtrl && wnd != &m_modifierListCtrl && wnd != &m_viewListCtrl && wnd != &m_inputListCtrl && wnd != m_view )
	{
		__super::OnContextMenu( pWnd, pos );
		return;
	}

	if ( wnd == &m_stateListCtrl )
	{
		TVHITTESTINFO hit;
		hit.pt = pos;
		m_stateListCtrl.ScreenToClient( &hit.pt );
		m_stateListCtrl.HitTest( &hit );
		if ( !hit.hItem )
		{
			__super::OnContextMenu( pWnd, pos );
			return;
		}
		m_stateListCtrl.SetFocus();
		if ( m_vStates.size() != 1 && m_stateListCtrl.GetSelectedItem() == hit.hItem )
			m_stateListCtrl.SelectItem( 0 );
		m_stateListCtrl.SelectItem( hit.hItem );
	}

	// Add in some handling of a click in the modifier list ctrl (non-existing yet)
	bool isModifier = false;
	bool isView = false;
	bool isInput = false;

	CAG2ModifierBasePtr pModifier = NULL;
	if ( wnd == &m_modifierListCtrl )
	{
		TVHITTESTINFO hit;
		hit.pt = pos;
		m_modifierListCtrl.ScreenToClient( &hit.pt );
		m_modifierListCtrl.HitTest( &hit );
		if ( !hit.hItem )
		{
			__super::OnContextMenu( pWnd, pos );
			return;
		}
		m_modifierListCtrl.SetFocus();
		if ( m_modifierListCtrl.GetSelectedItem() == hit.hItem )
			m_modifierListCtrl.SelectItem( 0 );

		m_modifierListCtrl.SelectItem( hit.hItem );
		pModifier = m_pGraph->GetModifier(m_modifierListCtrl.GetItemData(hit.hItem));
		if (pModifier)
			isModifier = true;
	}

	CAGState2* pState = m_vStates.size() == 1 ? m_vStates[0] : NULL;
	if ( wnd == m_view )
	{
		CPoint local( pos );
		m_view->ScreenToClient( &local );
		// Make a difference between regular states and modifier states
		CAGNodeBase2* pBaseNode = (CAGNodeBase2*) m_view->GetNodeAtPoint( local );
		if (pBaseNode->GetAGNodeType() == AG_NODE_MODIFIER)
		{
			isModifier = true;
			pModifier = ((CAG2ModifierNode*)pBaseNode)->GetModifier();
		}
		else
		{
			CAGNode2* pNode = (CAGNode2*) pBaseNode;
			if ( pNode )
			{
				pState = pNode->GetState();
			}
		}
	}

	CAGView2Ptr pView = NULL;
	if(wnd == &m_viewListCtrl)
	{
		TVHITTESTINFO hit;
		hit.pt = pos;
		m_viewListCtrl.ScreenToClient( &hit.pt );
		m_viewListCtrl.HitTest( &hit );
		if ( !hit.hItem )
		{
			__super::OnContextMenu( pWnd, pos );
			return;
		}
		m_viewListCtrl.SetFocus();
		if ( m_viewListCtrl.GetSelectedItem() == hit.hItem )
			m_viewListCtrl.SelectItem( 0 );

		m_viewListCtrl.SelectItem( hit.hItem );
		pView = m_pGraph->FindView(m_viewListCtrl.GetItemText(hit.hItem));
		if (pView)
			isView = true;
	}

	CAGInput2Ptr pInput = NULL;
	if(wnd == &m_inputListCtrl)
	{
		TVHITTESTINFO hit;
		hit.pt = pos;
		m_inputListCtrl.ScreenToClient( &hit.pt );
		m_inputListCtrl.HitTest( &hit );
		if ( !hit.hItem )
		{
			__super::OnContextMenu( pWnd, pos );
			return;
		}
		m_inputListCtrl.SetFocus();
		if ( m_inputListCtrl.GetSelectedItem() == hit.hItem )
			m_inputListCtrl.SelectItem( 0 );

		m_inputListCtrl.SelectItem( hit.hItem );
		pInput = m_pGraph->FindInput(m_inputListCtrl.GetItemText(hit.hItem));
		if (pInput)
			isInput = true;
	}

	if (isModifier)
	{
		// modifier PopUp menu
		ModifierStatePopupMenu(pModifier, wnd, pos);
	}
	else if(isView)
	{
		//View PopUp menu
		ViewPopupMenu(pView, wnd, pos);
	}
	else if(isInput)
	{
		//Input PopUp menu
		InputPopupMenu(pInput, wnd, pos);
	}
	else
	{
		// Animation State PopUp menu
		AnimationStatePopupMenu(pState, wnd, pos);
	}


}

void CAnimationGraphDialog2::OnSize(UINT nType, int cx, int cy)
{
	__super::OnSize(nType, cx, cy);
	if (::IsWindow(m_rollupCtrl.m_hWnd))
		m_rollupCtrl.Invalidate();
}

void CAnimationGraphDialog2::OnIconSizeChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMXTPCONTROL* tagNMCONTROL = (NMXTPCONTROL*)pNMHDR;
	CXTPControlComboBox* pControl = (CXTPControlComboBox*)tagNMCONTROL->pControl;
	if (pControl->GetType() == xtpControlComboBox)
	{
		int sel = pControl->GetCurSel();
		if (sel != CB_ERR)
		{
			const IconSize& iconSize = m_iconSizes[sel];
			m_pCAnimationImageManager->SetImageSize(iconSize);

			// Invalidate the entire view.
			SetActiveView(m_pView);
		}
	}
	*pResult = 1;
}

void CAnimationGraphDialog2::OnUpdateIconSizeUI(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(m_enableIcons->GetIVal());

	if (m_iconSizes[m_displayedIconSize->GetIVal()] != m_pCAnimationImageManager->GetImageSize())
	{
		CXTPControlComboBox *pControl = (CXTPControlComboBox*)m_wndToolBar->GetControls()->FindControl(xtpControlComboBox, ID_ANIMATION_GRAPH_ICON_SIZE, TRUE, FALSE);
		if (!pControl || pControl->GetType() != xtpControlComboBox)
			return;
		int sel = CB_ERR;
		IconSize iconSize = m_pCAnimationImageManager->GetImageSize();
		for (int index = 0; index < int(m_iconSizes.size()); ++index)
		{
			if (iconSize == m_iconSizes[index])
				sel = index;
		}

		if (sel != CB_ERR && sel != pControl->GetCurSel())
			pControl->SetCurSel(sel);

		ReadDisplayedIconSize();
	}
}

void CAnimationGraphDialog2::ReadDisplayedIconSize()
{
	CXTPControlComboBox *pControl = (CXTPControlComboBox*)m_wndToolBar->GetControls()->FindControl(xtpControlComboBox, ID_ANIMATION_GRAPH_ICON_SIZE, TRUE, FALSE);
	if (!pControl || pControl->GetType() != xtpControlComboBox)
		return;

	if (pControl->GetCurSel() != CB_ERR)
		m_displayedIconSize->Set(pControl->GetCurSel());
	else
		m_displayedIconSize->Set(0);
}

void CAnimationGraphDialog2::OnDisplayIconsChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMXTPCONTROL* tagNMCONTROL = (NMXTPCONTROL*)pNMHDR;
	CXTPControlButton* pControl = (CXTPControlButton*)tagNMCONTROL->pControl;
	if (pControl->GetType() == xtpControlButton)
	{
		pControl->SetChecked(!pControl->GetChecked());
		EnableIcons(pControl->GetChecked());
	}
	*pResult = 1;
}

void CAnimationGraphDialog2::OnUpdateDisplayIconsUI(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(TRUE);

	CXTPControlButton *pControl = (CXTPControlButton*)m_wndToolBar->GetControls()->FindControl(xtpControlButton, ID_ANIMATION_GRAPH_ICONS, TRUE, FALSE);
	if (!pControl || pControl->GetType() != xtpControlButton)
		return;

	pControl->SetChecked(m_enableIcons->GetIVal());
}

void CAnimationGraphDialog2::OnDisplayPreviewChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMXTPCONTROL* tagNMCONTROL = (NMXTPCONTROL*)pNMHDR;
	CXTPControlButton* pControl = (CXTPControlButton*)tagNMCONTROL->pControl;
	if (pControl->GetType() == xtpControlButton)
	{
		pControl->SetChecked(!pControl->GetChecked());
		EnablePreview(pControl->GetChecked());
	}
	*pResult = 1;
}

void CAnimationGraphDialog2::OnUpdateDisplayPreviewUI(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(TRUE);

	CXTPControlButton *pControl = (CXTPControlButton*)m_wndToolBar->GetControls()->FindControl(xtpControlButton, ID_ANIMATION_GRAPH_PREVIEW, TRUE, FALSE);
	if (!pControl || pControl->GetType() != xtpControlButton)
		return;

	pControl->SetChecked(m_preview->GetIVal());
}

//////////////////////////////////////////////////////////////////////////
LRESULT CAnimationGraphDialog2::OnDockingPaneNotify(WPARAM wParam, LPARAM lParam)
{
	if (wParam == XTP_DPN_SHOWWINDOW)
	{
		// get a pointer to the docking pane being shown.
		CXTPDockingPane* pwndDockWindow = (CXTPDockingPane*)lParam;
		if (!pwndDockWindow->IsValid())
		{
			switch (pwndDockWindow->GetID())
			{
			case IDW_ANIMGRAPH_STATES_PANE:
				pwndDockWindow->Attach(&m_stateListCtrl);
				m_stateListCtrl.SetOwner( this );
				break;
			case IDW_ANIMGRAPH_VIEWS_PANE:
				pwndDockWindow->Attach(&m_viewListCtrl);
				m_viewListCtrl.SetOwner( this );
				break;
			case IDW_ANIMGRAPH_INPUTS_PANE:
				pwndDockWindow->Attach(&m_inputListCtrl);
				m_inputListCtrl.SetOwner( this );
				break;
			case IDW_ANIMGRAPH_STATE_EDITOR_PANE:
				pwndDockWindow->Attach(m_stateEditor.GetPanel());
				m_stateEditor.GetPanel()->SetOwner( this );
				break;
			case IDW_ANIMGRAPH_STATE_PARAMS_PANE:
				pwndDockWindow->Attach(&m_stateParamsCtrl);
				m_stateParamsCtrl.SetOwner( this );
				break;
			case IDW_ANIMGRAPH_TEST_PANE:
				//pwndDockWindow->Attach(&m_tester);
				//m_tester.SetOwner( this );
				break;
			case IDW_ANIMGRAPH_STATE_QUERY_PANE:
				pwndDockWindow->Attach(&m_stateQuery);
				m_stateQuery.SetOwner( this );
				break;
			case IDW_ANIMGRAPH_PREVIEW_PANE:
				pwndDockWindow->Attach(&m_previewDialog);
				m_previewDialog.SetOwner( this );
				break;
			case IDW_ANIMGRAPH_ANIMATIONS_PANE:
				pwndDockWindow->Attach(&m_animationListView);
				m_animationListView.SetOwner(this);
				break;
			case IDW_ANIMGRAPH_PREVIEW_OPTIONS_PANE:
				pwndDockWindow->Attach(&m_rollupCtrl);
				m_rollupCtrl.SetOwner( this );
				break;
	
				// Animation Graph 2.0
			case IDW_ANIMGRAPH_MODIFIER_PANE:
				pwndDockWindow->Attach(&m_modifierListCtrl);
				m_modifierListCtrl.SetOwner( this );
				break;
			case IDW_ANIMGRAPH_DETAILS_PANE:
				pwndDockWindow->Attach(&m_genericNodeDetails);
				m_genericNodeDetails.SetOwner( this );
				break;

			default:
				return FALSE;
			}
		}
		return TRUE;
	}
	else if (wParam == XTP_DPN_CLOSEPANE)
	{
		// get a pointer to the docking pane being shown.
		CXTPDockingPane* pwndDockWindow = (CXTPDockingPane*)lParam;
		if (pwndDockWindow->IsValid())
		{
			switch (pwndDockWindow->GetID())
			{
			case IDW_ANIMGRAPH_STATES_PANE:
				break;
			}
		}
	}

	return FALSE;
}

void CAnimationGraphDialog2::OnAGLinkMappingChanged()
{
	m_stateEditor.StateEvent( eSEE_InitContainer2 );
}

BOOL CAnimationGraphDialog2::OnViewPane( UINT cmdID )
{
	int pane = 0;
	switch ( cmdID )
	{
	case ID_VIEW_STATEQUERY:
			OnViewPaneStateQuery();
			return TRUE;
			break;
	case ID_VIEW_STATES:
		pane = IDW_ANIMGRAPH_STATES_PANE;
		break;
	case ID_VIEW_VIEWS:
		pane = IDW_ANIMGRAPH_VIEWS_PANE;
		break;
	case ID_VIEW_INPUTS:
		pane = IDW_ANIMGRAPH_INPUTS_PANE;
		break;
	case ID_VIEW_TESTING:
		//pane = IDW_ANIMGRAPH_TEST_PANE;
		return TRUE;
		break;
	case ID_VIEW_PREVIEW:
		pane = IDW_ANIMGRAPH_PREVIEW_PANE;
		break;
	case ID_VIEW_PREVIEWOPTIONS:
		pane = IDW_ANIMGRAPH_PREVIEW_OPTIONS_PANE;
		break;
	case ID_VIEW_STATEEDITOR:
		pane = IDW_ANIMGRAPH_STATE_EDITOR_PANE;
		break;
	case ID_VIEW_STATEPARAMS:
		pane = IDW_ANIMGRAPH_STATE_PARAMS_PANE;
		break;

		// Animation Graph 2.0
	case ID_VIEW_MODIFIERS:
		pane = IDW_ANIMGRAPH_MODIFIER_PANE;
		break;
	case ID_VIEW_DETAILS:
		pane = IDW_ANIMGRAPH_DETAILS_PANE;
		break;
	case ID_VIEW_ANIMATIONS:
		pane = IDW_ANIMGRAPH_ANIMATIONS_PANE;
		break;
	case ID_VIEW_VIEW:
		pane = IDW_ANIMGRAPH_VIEW_PANE;
		break;

	default:
		assert( !"invalid command id" );
		return FALSE;
	}
	m_paneManager.ShowPane( pane, TRUE );
	return TRUE;
}

void CAnimationGraphDialog2::OnViewPaneStateQuery()
{
	m_paneManager.ShowPane( IDW_ANIMGRAPH_STATE_QUERY_PANE, TRUE );
}

void CAnimationGraphDialog2::OnGraphAddState()
{
	if ( m_pGraph == NULL )
	{
		return;
	}

	CString name = GenerateName(m_pGraph, &CAnimationGraph2::FindState, "state");
	m_pGraph->AddState( new CAGState2(m_pGraph, name) );
	m_stateListCtrl.ReloadStates();
	m_tester.Reload();
	m_stateQuery.Reload( true );
	m_stateListCtrl.SelectItemByName(name);
}

void CAnimationGraphDialog2::OnGraphAddView()
{
	if ( m_pGraph == NULL )
	{
		return;
	}

	CString name = GenerateName(m_pGraph, &CAnimationGraph2::FindView, "view");
	m_pGraph->AddView( new CAGView2(m_pGraph, name) );
	m_viewListCtrl.ReloadViews();
	m_tester.Reload();
	m_viewListCtrl.SelectItemByName(name);
}

void CAnimationGraphDialog2::OnGraphAddInput()
{
	if ( m_pGraph == NULL )
	{
		return;
	}

	CString name = GenerateName(m_pGraph, &CAnimationGraph2::FindInput, "input");
	m_pGraph->AddInput( new CAGInput2(m_pGraph, name) );
	m_inputListCtrl.ReloadInputs();
	m_tester.Reload();
	m_stateQuery.Reload( true );
	m_inputListCtrl.SelectItemByName(name);
}

void CAnimationGraphDialog2::OnGraphCreateAnimation()
{
	AfxMessageBox("Not yet implemented, sorry.");
}

void CAnimationGraphDialog2::OnGraphIslandReport()
{
	if (m_pGraph)
	{
		ViewReport( GenerateIslandReport(m_pGraph) );
	}
}

void CAnimationGraphDialog2::OnGraphBadNullNodeReport()
{
	if (m_pGraph)
	{
		ViewReport( GenerateNullNodesWithNoForceLeaveReport2(m_pGraph) );
	}
}

void CAnimationGraphDialog2::OnGraphOrphanNodesReport()
{
	if (m_pGraph)
	{
		ViewReport( GenerateOrphanNodesReport2(m_pGraph) );
	}
}

void CAnimationGraphDialog2::OnGraphSpeedReport()
{
	CString filename;
	if (CFileUtil::SelectSingleFile( EFILE_TYPE_ANY,filename,CHARACTER_FILE_FILTER ))
	{
		if (ICharacterInstance * pInstance = GetISystem()->GetIAnimationSystem()->CreateInstance(filename))
		{
			ViewReport( GenerateSpeedReport2(pInstance->GetIAnimationSet()) );
			pInstance->Release();
		}
		else
			AfxMessageBox("Couldn't create character " + filename);
	}
}

void CAnimationGraphDialog2::OnGraphBadCALReport()
{
	if ( m_pGraph == NULL )
	{
		return;
	}

	CString filename;
	if (CFileUtil::SelectSingleFile( EFILE_TYPE_ANY,filename,CHARACTER_FILE_FILTER ))
	{
		if (ICharacterInstance * pInstance = GetISystem()->GetIAnimationSystem()->CreateInstance(filename))
		{
			ViewReport( GenerateBadCALReport2(pInstance->GetIAnimationSet(), m_pGraph) );
			pInstance->Release();
		}
		else
			AfxMessageBox("Couldn't create character " + filename);
	}
}

void CAnimationGraphDialog2::OnGraphMatchSpeeds()
{
	if ( m_pGraph == NULL )
	{
		return;
	}

	CString filename;
	if (CFileUtil::SelectSingleFile( EFILE_TYPE_ANY,filename,CHARACTER_FILE_FILTER ))
	{
		if (ICharacterInstance * pInstance = GetISystem()->GetIAnimationSystem()->CreateInstance(filename))
		{
			ViewReport( MatchMovementSpeedsToAnimations2(pInstance->GetIAnimationSet(), m_pGraph) );
			pInstance->Release();
		}
		else
			AfxMessageBox("Couldn't create character " + filename);
	}
}

void CAnimationGraphDialog2::OnGraphDeadInputReport()
{
	if ( m_pGraph == NULL )
	{
		return;
	}

	ViewReport( GenerateDeadInputsReport2( m_pGraph ) );
}

void CAnimationGraphDialog2::OnGraphTransitionLengthReport()
{
	if ( m_pGraph == NULL )
	{
		return;
	}

	CString out;
	FindLongTransitions( out, m_pGraph, 2 );
	ViewReport( out );
}

void CAnimationGraphDialog2::ViewReport( const CString& report )
{
	FILE * f = fopen("animation_graph_report.txt", "wt");
	if (f)
	{
		fwrite( (const char *)report, report.GetLength(), 1, f );
		fclose(f);
		ShellExecute( GetSafeHwnd(), "open", "animation_graph_report.txt", NULL, ".", SW_SHOW );
	}
}

void CAnimationGraphDialog2::OnGraphTrial()
{
	CString errorString;

	if (m_pGraph)
	{
		XmlNodeRef graph = m_pGraph->ToXml();
		if (graph)
		{
			CString filename = m_pGraph->GetFilename();
			filename = PathUtil::GetFile( (const char*)filename );
			if (!GetISystem()->GetIAnimationGraphSystem()->TrialAnimationGraph( filename, graph ))
				errorString = "Unable to load animation graph into game engine";
		}
		else
		{
			errorString = "Unable to convert graph to XML";
		}
	}

	if (!errorString.IsEmpty())
		AfxMessageBox( errorString );
}




//////////////////////////////////////////////////////////////////////////
// CAnimationGraphListCtrl2
//////////////////////////////////////////////////////////////////////////

BEGIN_MESSAGE_MAP(CAnimationGraphListCtrl2, CTreeCtrl)
	ON_WM_SIZE()
	ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

BOOL CAnimationGraphListCtrl2::OnEraseBkgnd(CDC* pDC)
{
	return FALSE;
}

void CAnimationGraphListCtrl2::OnSize(UINT nType, int cx, int cy)
{
	__super::OnSize(nType, cx, cy);
	Invalidate();
}

BOOL CAnimationGraphListCtrl2::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
	BOOL ret = __super::Create( dwStyle|WS_BORDER|TVS_HASBUTTONS|/*TVS_LINESATROOT|*/TVS_HASLINES|TVS_SHOWSELALWAYS,rect,pParentWnd,nID );

	CMFCUtils::LoadTrueColorImageList( m_imageList, IDB_ANIMATIONGRAPH2_COMPONENTS /*IDB_HYPERGRAPH_COMPONENTS*/,20 /*16*/,RGB(255,0,255) );
	SetImageList( &m_imageList,TVSIL_NORMAL );
	SetItemHeight(18 /*14*/);

	return ret;
}

inline bool CompareNames( const CAnimationGraphListCtrl2::TNameIcon& ni1, const CAnimationGraphListCtrl2::TNameIcon& ni2 )
{
	return ni1.first < ni2.first;
}

void CAnimationGraphListCtrl2::AddList( std::vector< TNameIcon >& items)
{
	std::sort( items.begin(), items.end(), CompareNames );
	for (std::vector< TNameIcon >::const_iterator iter = items.begin(); iter != items.end(); ++iter )
	{
		InsertItem( iter->first, iter->second, iter->second );
	}
}

void CAnimationGraphListCtrl2::ReloadStates()
{
	SetRedraw(FALSE);
	SelectItem(0);
	DeleteAllItems();

	if (CAnimationGraph2Ptr pGraph = m_pParent->GetAnimationGraph())
	{
		std::set< CString > parents;

		std::vector< TNameIcon > items;
		for (CAnimationGraph2::state_iterator iter = pGraph->StateBegin(); iter != pGraph->StateEnd(); ++iter)
		{
			CAGState2* pState = *iter;
			if ( CAGState2* pParent = pState->GetParent() )
				parents.insert( pParent->GetName() );
					
			int icon = 1;

			if (!pState->IncludeInGame())
				icon = 1;
			else if(!pState->AllowSelect() && pState->GetAnimationName().IsEmpty())
				icon = 4;
			else if(!pState->AllowSelect())
				icon = 2;
			else if (pState->AllowSelect())
				icon = 3;

			if ( !pState->IsNullState() )
				icon += 3;

			items.push_back( TNameIcon(pState->GetName(), icon) );
		}
		AddList( items );

		// Look at all of the state items and make the parent states bold
		TCHAR szText[1024];
		TVITEM item;
		item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_STATE;
		item.pszText = szText;
		item.cchTextMax = 1024;
		for ( item.hItem = GetRootItem(); item.hItem; item.hItem = GetNextItem(item.hItem, TVGN_NEXT) )
		{
			if ( GetItem(&item) )
			{
				if ( parents.find(item.pszText) == parents.end() )
					continue;
				item.state = TVIS_BOLD;
				item.stateMask = TVIS_BOLD;
				SetItem(&item);
				item.stateMask = 0;
			}
		}
	}

	SetRedraw(TRUE);
	RedrawWindow(0, 0, RDW_UPDATENOW);
}

void CAnimationGraphListCtrl2::ReloadModifiers()
{
	SetRedraw(FALSE);
	SelectItem(0);
	DeleteAllItems();

	if (CAnimationGraph2Ptr pGraph = m_pParent->GetAnimationGraph())
	{
		// Go through all existing modifiers and add them in here
//		std::vector< TNameIcon > items;
		CAnimationGraph2::modifier_iterator iterEnd = pGraph->ModifiersEnd();
		for (CAnimationGraph2::modifier_iterator iter = pGraph->ModifiersBegin(); iter != iterEnd; ++iter)
		{
			HTREEITEM newItem = InsertItem( iter->second->GetListDisplayString(), 13, 13 );
			SetItemData(newItem, iter->second->GetId());
			//items.push_back( TNameIcon(iter->second->GetListDisplayString(), 11) );
		}
		//AddList( "Modifiers", items );
	}

	SetRedraw(TRUE);
	RedrawWindow(0, 0, RDW_UPDATENOW);
}

void CAnimationGraphListCtrl2::ReloadViews()
{
	SetRedraw(FALSE);
	SelectItem(0);
	DeleteAllItems();

	if (CAnimationGraph2Ptr pGraph = m_pParent->GetAnimationGraph())
	{
		std::vector< TNameIcon > items;
		for (CAnimationGraph2::view_iterator iter = pGraph->ViewBegin(); iter != pGraph->ViewEnd(); ++iter)
			items.push_back( TNameIcon((*iter)->GetName(),9) );
		AddList( items );
	}

	SetRedraw(TRUE);
	RedrawWindow(0, 0, RDW_UPDATENOW);
}

bool CAnimationGraphListCtrl2::IsInputUsed(CAGInput2Ptr pInput)
{
	if (CAnimationGraph2Ptr pGraph = m_pParent->GetAnimationGraph())
	{
		for (CAnimationGraph2::state_iterator iter = pGraph->StateBegin(); iter != pGraph->StateEnd(); ++iter)
		{
			CAGState2Ptr pState = *iter;

			if(pState == NULL)
				continue;

			if (pState->IsInputUsed(pInput))
			{
				return true;
			}
		}
	}

	return false;
}

void CAnimationGraphListCtrl2::ReloadInputs()
{
	SetRedraw(FALSE);
	SelectItem(0);
	DeleteAllItems();

	if (CAnimationGraph2Ptr pGraph = m_pParent->GetAnimationGraph())
	{
		std::vector< TNameIcon > items;
		std::set<string> unusedInputs;
		for (CAnimationGraph2::input_iterator iter = pGraph->InputBegin(); iter != pGraph->InputEnd(); ++iter)
		{
			bool isUsed = true;
			CAGInput2* pInput = *iter;
			if (!IsInputUsed(pInput))
			{
				unusedInputs.insert(string(pInput->GetName()));
				isUsed = false;
			}

			EAnimationGraphInputType iType = pInput->GetType();
			items.push_back( TNameIcon(pInput->GetName(), !isUsed?1:iType==eAGIT_Float?10:iType==eAGIT_Integer?11:12) );
		}

		AddList( items );

		TCHAR szText[1024];
		TVITEM item;
		item.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_STATE;
		item.pszText = szText;
		item.cchTextMax = 1024;

		for ( item.hItem = GetRootItem(); item.hItem; item.hItem = GetNextItem(item.hItem, TVGN_NEXT) )
		{
			if ( GetItem(&item) )
			{
				if ( unusedInputs.find(item.pszText) == unusedInputs.end() )
					continue;
				item.state = TVIS_BOLD;
				item.stateMask = TVIS_BOLD;
				SetItem(&item);

				item.stateMask = 0;
			}
		}
	}

	SetRedraw(TRUE);
	RedrawWindow(0, 0, RDW_UPDATENOW);
}

void CAnimationGraphListCtrl2::SelectItemByName( const CString& state )
{
	for (HTREEITEM item = GetRootItem(); item; item = GetNextSiblingItem(item))
	{
		if (state == GetItemText(item))
		{
			SelectItem( item );
			return;
		}
	}
	SelectItem(NULL);
}


//////////////////////////////////////////////////////////////////////////
BOOL CAnimationGraphDialog2::PreTranslateMessage(MSG* pMsg)
{
	bool bFramePreTranslate = true;
	if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
	{
		CWnd* pWnd = CWnd::GetFocus();
		if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CEdit)))
			bFramePreTranslate = false;
	}

	if (bFramePreTranslate)
	{
		// allow tooltip messages to be filtered
		if (__super::PreTranslateMessage(pMsg))
			return TRUE;
	}

	if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
	{
		// All keypresses are translated by this frame window
		::TranslateAccelerator(m_hWnd, m_hAccelerators, pMsg);
		::TranslateMessage(pMsg);
		::DispatchMessage(pMsg);

		return TRUE;
	}

	return FALSE;
}

void CAnimationGraphDialog2::EnableIcons(bool enableIcons)
{
	if (m_enableIcons->GetIVal() != int(enableIcons))
	{
		m_enableIcons->Set(enableIcons);
		if (m_pGraph)
			m_pGraph->ShowIcons(enableIcons);

		// Invalidate the entire view.
		SetActiveView(m_pView);
	}
}

void CAnimationGraphDialog2::EnablePreview(bool enablePreview)
{
	if (m_preview->GetIVal() != int(enablePreview))
	{
		m_preview->Set(enablePreview);
		m_previewManager.EnablePreview(enablePreview);
	}
}

void CAnimationGraphDialog2::RegisterConsoleVariables()
{
	m_displayedIconSize = gEnv->pConsole->GetCVar("ag_icon_size");
	if (!m_displayedIconSize)
	{
		m_displayedIconSize = REGISTER_INT("ag_icon_size",0,0,
			"Size of icons on the animation graph (0-4).\n"
			"Default is 0.");
	}

	m_enableIcons = gEnv->pConsole->GetCVar("ag_display_icons");
	if (!m_enableIcons)
	{
		m_enableIcons = REGISTER_INT("ag_display_icons",1,0,
			"Flag indicating whether icons are displayed on the animation graph.\n"
			"Default is 1.");
	}

	m_preview = gEnv->pConsole->GetCVar("ag_preview");
	if (!m_preview)
	{
		m_preview = REGISTER_INT("ag_preview", 1, 0,
			"Flag indicating whether animations are previewed in the preview window of the animation graph.\n"
			"Default is 1.");
	}
}

void CAnimationGraphDialog2::OnStateParamSelChanged()
{
	if ( ::IsWindow(m_stateParamsCtrl) )
	{
		m_stateEditor.OnStateParamSelChanged(
			m_stateParamsCtrl.m_CurrentSelection.empty() ? NULL : &m_stateParamsCtrl.m_CurrentSelection,
			m_pView ? m_pView->GetName() : "" );

		TParameterizationId2::const_iterator it;
		TParameterizationId2::const_iterator itEnd = m_stateParamsCtrl.m_CurrentSelection.end();
		
		for ( it = m_stateParamsCtrl.m_CurrentSelection.begin(); it != itEnd; ++it )
			if ( !it->second.IsEmpty() )
				m_previewManager.SetParameter( it->first, it->second );
	}
}


void CAnimationGraphDialog2::SelectState(const CString& stateName, bool bIgnoreDependencies)
{
	if(bIgnoreDependencies)
		++m_nBlockSelChanged;
	m_stateListCtrl.SelectItemByName( stateName );
	if(bIgnoreDependencies)
		--m_nBlockSelChanged;
}


void CAnimationGraphDialog2::OnGraphDefaultSettingsDialog()
{
	// start the dialog window with all the different
	// node default settings
	m_defaultsDialog.DoModal();

	if (!m_pGraph)
		return;

	// maybe reload character if it has changed
	CString newCharName = m_pGraph->GetCharacterName();
	const CString loadedCharName = m_previewDialog.GetCharacterName();
	if (newCharName != loadedCharName)
	{
		m_previewDialog.SetCharacter( newCharName.IsEmpty() ? AnimationGraphDialogHelpers2::GetDefaultCharacterName() : newCharName );
	}
}

void CAnimationGraphDialog2::OnGraphVersionInfo()
{
	AfxMessageBox("AnimationGraph Version 1.5\n\n\
Compatibility Issues when Converting from 1.0 Graph to 1.5:\n\
- Transition Times and Playback Speed in parameterized states that are overridden\n\
  in sub-parameterizations are not converted. Only one transition time and playback\n\
  speed per state is supported.\n\
- Animations on multiple layers within one state are no longer supported for\n\
  better flow control. Warning message will appear, use Additive Modifier to\n\
  start animations on additional layers\n\
- Custom Template	Nodes added that were not shipped with AnimationGraph 1.0\n\
  will not be automatically converted.\n\
  Create a custom Modifier to re-integrate them into AG 1.5\n\
- WaitForKeyTime (CA_START_AT_KEYFRAME flag) parameter has been removed\n\
  (unused in Crysis 1 and SDK graph, so no compatibility issues)\n\
- Custom additional	Template Nodes defined in Parent states are not inherited by the child states\n\
- ForceStartImmediately is no longer available in the graph, because the flags affected\n\
  by it are obsolete and are no longer in use.\n\
- Events and other template nodes/extra parameters that read in custom template\n\
  parameter values (such as $name) will not work. Conversion will create dummy\n\
  Modifiers for these case. This is valid with the exception of Outputs, which\n\
  support custom template parameters\n\
- Custom Template: Animation Names using unusual template parameter names might\n\
  not be found by the conversion code.\n");
}

void CAnimationGraphDialog2::AnimationStatePopupMenu( CAGState2* pState, CWnd* wnd, CPoint &pos )
{
	if ( !pState )
	{
		__super::OnContextMenu( wnd, pos );
		return;
	}

	CMenu menu;
	CMenu viewMenu, fromMenu, toMenu, childMenu, activeParamMenu, excludedParamMenu, modifiersMenu;
	VERIFY( menu.CreatePopupMenu() );
	VERIFY( viewMenu.CreatePopupMenu() );
	VERIFY( fromMenu.CreatePopupMenu() );
	VERIFY( toMenu.CreatePopupMenu() );
	VERIFY( childMenu.CreatePopupMenu() );
	VERIFY( activeParamMenu.CreatePopupMenu() );
	VERIFY( excludedParamMenu.CreatePopupMenu() );
	VERIFY( modifiersMenu.CreatePopupMenu() );

	int id = 15000;
	for ( CAnimationGraph2::view_iterator it = m_pGraph->ViewBegin(); it != m_pGraph->ViewEnd(); ++it )
	{
		CAGView2Ptr pView = *it;
		if ( pView->HasState(pState) )
			viewMenu.AppendMenu( MF_STRING | ( m_pView == pView ? MF_CHECKED : 0 ), id++, pView->GetName() );
	}
	int idStates = id;
	std::vector< CAGState2Ptr > states;
	m_pGraph->StatesLinkedTo( states, pState );
	std::vector< CAGState2Ptr >::iterator it, itEnd = states.end();
	for ( it = states.begin(); it != itEnd; ++it )
	{
		CAGState2* pStateIt = *it;
		fromMenu.AppendMenu( MF_STRING, id++, pStateIt->GetName() );
	}
	states.clear();
	m_pGraph->StatesLinkedFrom( states, pState );
	itEnd = states.end();
	for ( it = states.begin(); it != itEnd; ++it )
	{
		CAGState2Ptr pStateIt = *it;
		toMenu.AppendMenu( MF_STRING, id++, pStateIt->GetName() );
	}
	states.clear();
	m_pGraph->ChildStates( states, pState );
	itEnd = states.end();
	for ( it = states.begin(); it != itEnd; ++it )
	{
		CAGState2Ptr pStateIt = *it;
		childMenu.AppendMenu( MF_STRING, id++, pStateIt->GetName() );
	}

	menu.AppendMenu( MF_STRING, id++, _T("Clone") );
	menu.AppendMenu( MF_STRING, id++, _T("Delete") );
	menu.AppendMenu( MF_SEPARATOR );

	// Create active and excluded parameters menu lists
	int idStateParams = id;
	std::vector< TParameterizationId2 > paramIds;
	pState->GetParameterizations( paramIds );
	std::vector< TParameterizationId2 >::const_iterator itIds;
	for ( itIds = paramIds.begin(); itIds != paramIds.end(); ++itIds )
	{
		if ( pState->IsParameterizationExcluded( &(*itIds) ) )
		{
			excludedParamMenu.AppendMenu( MF_STRING, id++, itIds->AsString() );
		}
		else
		{
			activeParamMenu.AppendMenu( MF_STRING, id++, itIds->AsString() );
		}
	}

	int idModifiers = id;
	for ( int i = 0; i < pState->GetLinkedModifierCount(); ++i )
	{
		int modifierId = pState->GetLinkedModifier( i );
		CAG2ModifierBasePtr pModifier = m_pGraph->GetModifier( modifierId );
		CString modifierName = pModifier->GetListDisplayString();
		modifiersMenu.AppendMenu( MF_STRING, id++, modifierName );
	}


	menu.AppendMenu( MF_POPUP | (viewMenu.GetMenuItemCount() ? 0 : MF_GRAYED), (UINT) viewMenu.m_hMenu, _T("Find in View") );
	menu.AppendMenu( MF_SEPARATOR );
	menu.AppendMenu( MF_POPUP | (fromMenu.GetMenuItemCount() ? 0 : MF_GRAYED), (UINT) fromMenu.m_hMenu, _T("Linked From") );
	menu.AppendMenu( MF_POPUP | (toMenu.GetMenuItemCount() ? 0 : MF_GRAYED), (UINT) toMenu.m_hMenu, _T("Linked To") );
	menu.AppendMenu( MF_POPUP | (modifiersMenu.GetMenuItemCount() ? 0 : MF_GRAYED), (UINT) modifiersMenu.m_hMenu, _T("Modifiers") );
	menu.AppendMenu( MF_POPUP | (childMenu.GetMenuItemCount() ? 0 : MF_GRAYED), (UINT) childMenu.m_hMenu, _T("Child States") );
	menu.AppendMenu( MF_SEPARATOR );
	menu.AppendMenu( MF_POPUP | (activeParamMenu.GetMenuItemCount() ? 0 : MF_GRAYED), (UINT) activeParamMenu.m_hMenu, _T("Active Param Combinations") );
	menu.AppendMenu( MF_POPUP | (excludedParamMenu.GetMenuItemCount() ? 0 : MF_GRAYED), (UINT) excludedParamMenu.m_hMenu, _T("Excluded Param Combinations") );
	
	if ( wnd == m_view )
	{
		menu.AppendMenu( MF_SEPARATOR );
		menu.AppendMenu( MF_STRING, IDC_REMOVE_FROM_VIEW, _T("Remove from View") );
		menu.AppendMenu( MF_STRING, IDC_REMOVE_DISCONNECT, _T("Remove and Disconnect") );
	}

	// track menu	
	int nMenuResult = CXTPCommandBars::TrackPopupMenu( &menu, TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x, pos.y, this, NULL );

	if ( nMenuResult == IDC_REMOVE_DISCONNECT )
	{
		// Remove and Disconnect
		m_view->SendMessage( WM_COMMAND, ID_EDIT_DELETE, 0 );
	}
	else if ( nMenuResult == IDC_REMOVE_FROM_VIEW )
	{
		// Remove from View
		m_view->SendMessage( WM_COMMAND, ID_EDIT_DELETE_KEEP_LINKS, 0 );
	}
	if ( nMenuResult >= 15000 && nMenuResult < idStates )
	{
		CWaitCursor wait;
		CString view;
		viewMenu.GetMenuString( nMenuResult, view, MF_BYCOMMAND );
		CAGView2Ptr pView = m_pGraph->FindView( view );
		if ( pView != m_pView )
		{
			SetActiveView( pView );
			m_viewListCtrl.SelectItemByName( view );
		}
		CHyperNode* pNode = m_pView->GetNodeForState( pState );
		if ( pNode )
			m_view->ShowAndSelectNode( pNode, true );
		m_stateListCtrl.SelectItemByName( pState->GetName() );
		m_view->SetFocus();
	}
	else if ( nMenuResult >= idStates && nMenuResult < idStateParams )
	{
		CWaitCursor wait;
		CString state;
		if (!fromMenu.GetMenuString( nMenuResult, state, MF_BYCOMMAND ))
			if (!toMenu.GetMenuString( nMenuResult, state, MF_BYCOMMAND ))
				childMenu.GetMenuString( nMenuResult, state, MF_BYCOMMAND );

		HTREEITEM hState = m_stateListCtrl.GetRootItem();
		while ( hState && m_stateListCtrl.GetItemText(hState) != state )
			hState = m_stateListCtrl.GetNextItem( hState, TVGN_NEXT );
		if ( hState )
		{
			m_stateListCtrl.EnsureVisible( hState );
			m_stateListCtrl.SelectItem( hState );
			SetActiveState( m_pGraph->FindState(state) );
			if ( m_pView )
			{
				CHyperNode* pNode = m_pView->GetNodeForState( pState );
				if ( pNode )
					m_view->ShowAndSelectNode( pNode, true );
			}
		}

		if (state.IsEmpty())
		{
			if (menu.GetMenuString( nMenuResult, state, MF_BYCOMMAND ))
			{
				if(state.Compare("Clone") == 0)
				{
					if (IDYES == AfxMessageBox( "Clone " + pState->GetName() + " State?\n", MB_YESNO ))
					{
						pState->GetGraph()->CloneState( pState );
					}	
				}
				else if(state.Compare("Delete") == 0)
				{
					IAGCheckedOperation2Ptr pOp = pState->CreateDeleteOp();
					if (IDYES == AfxMessageBox( "Delete " + pState->GetName() + " State?\n\n" + pOp->GetExplanation(), MB_YESNO ))
					{
						pOp->Perform();
						m_stateEditor.ClearActiveItem();
					}
				}
			}
		}
	}
	else if ( nMenuResult >= idStateParams && nMenuResult < idModifiers )
	{
		// TODO: Handle state params here...
	}
	else if ( nMenuResult >= idModifiers )
	{
		int linkedModifierIndex = nMenuResult - idModifiers;
		if ( pState->GetLinkedModifierCount() <= linkedModifierIndex )
		{
 			return;
 		}
	
		int modifierId = pState->GetLinkedModifier( linkedModifierIndex );
 		CAG2ModifierBasePtr pModifier = m_pGraph->GetModifier( modifierId );
		 
 		SetActiveState( CAGState2Ptr( NULL ) );
 		m_pGraph->GetModifierManager()->SetSelectedModifier( pModifier );
 
 		HTREEITEM hState = m_modifierListCtrl.GetRootItem();
 		while ( hState && m_modifierListCtrl.GetItemData( hState ) != modifierId )
 		{
 			hState = m_modifierListCtrl.GetNextItem( hState, TVGN_NEXT );
 		}
 
 		if ( ! hState )
 		{
 			return;
 		}
 
 		m_modifierListCtrl.EnsureVisible( hState );
 		m_modifierListCtrl.SelectItem( hState );
	}
}

void CAnimationGraphDialog2::ModifierStatePopupMenu( CAG2ModifierBasePtr pModifier, CWnd* wnd, CPoint &pos )
{
	if ( !pModifier )
	{
		__super::OnContextMenu( wnd, pos );
		return;
	}

	CMenu menu;
	CMenu modifierMenu;
	VERIFY( menu.CreatePopupMenu() );
	VERIFY( modifierMenu.CreatePopupMenu() );

	if ( wnd == m_view )
	{
		menu.AppendMenu( MF_SEPARATOR );
		menu.AppendMenu( MF_STRING, IDC_REMOVE_FROM_VIEW, _T("Remove from View") );
	}
	menu.AppendMenu( MF_STRING, IDC_DELETE_COMPLETELY, _T("Delete Completely") );

	// track menu	
	int nMenuResult = CXTPCommandBars::TrackPopupMenu( &menu, TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x, pos.y, this, NULL );

	if ( nMenuResult == IDC_DELETE_COMPLETELY )
	{
		// Delete Completely
		m_view->SendMessage( WM_COMMAND, ID_EDIT_DELETE, 0 );
		m_pGraph->GetModifierManager()->SetSelectedModifier(NULL);
		m_pGraph->RemoveModifier(pModifier);
		if (wnd == &m_modifierListCtrl)
		{
			CAGView2Ptr pView = m_pView;
			SetActiveView(NULL);
			SetActiveView(pView);
		}
	}
	else if ( nMenuResult == IDC_REMOVE_FROM_VIEW )
	{
		// Remove from View
		m_view->SendMessage( WM_COMMAND, ID_EDIT_DELETE_KEEP_LINKS, 0 );
	}
}

void CAnimationGraphDialog2::ViewPopupMenu( CAGView2Ptr pView, CWnd* wnd, CPoint &pos )
{
	if ( !pView )
	{
		__super::OnContextMenu( wnd, pos );
		return;
	}

	CMenu menu;
	CMenu modifierMenu;
	VERIFY( menu.CreatePopupMenu() );
	
	menu.AppendMenu( MF_STRING, IDC_DELETE, _T("Delete") );

	// track menu	
	int nMenuResult = CXTPCommandBars::TrackPopupMenu( &menu, TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x, pos.y, this, NULL );

	if ( nMenuResult == IDC_DELETE )
	{
		// Delete
		m_view->SendMessage( WM_COMMAND, ID_EDIT_DELETE, 0 );
		m_pGraph->RemoveView(pView);
	}
}

void CAnimationGraphDialog2::InputPopupMenu( CAGInput2Ptr pInput, CWnd* wnd, CPoint &pos )
{
	if ( !pInput )
	{
		__super::OnContextMenu( wnd, pos );
		return;
	}

	CMenu menu;
	CMenu modifierMenu;
	VERIFY( menu.CreatePopupMenu() );

	menu.AppendMenu( MF_STRING, IDC_DELETE, _T("Delete") );

	// track menu	
	int nMenuResult = CXTPCommandBars::TrackPopupMenu( &menu, TPM_NONOTIFY|TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON, pos.x, pos.y, this, NULL );

	if ( nMenuResult == IDC_DELETE )
	{
		// Delete
		m_pGraph->RemoveInput(pInput);
	}
}

void CAnimationGraphDialog2::UpdateGraphMenu()
{
	CXTPCommandBar* pAddModifierBar = GetCommandBars()->GetMenuBar()->GetControl(2)->GetCommandBar()->GetControl(3)->GetCommandBar();

	if (pAddModifierBar)
	{
		CMenu* subMenu = new CMenu();
		subMenu->CreatePopupMenu();
		CModifierManager* pModManager = m_pGraph->GetModifierManager();
		int modCount = pModManager->GetRegisteredModifierCount();
		for (int i = 0; i < modCount; ++i)
		{
			subMenu->AppendMenu( MF_STRING, ID_GRAPH_ADDMODIFIER_FIRST + i, pModManager->GetModifierHumanReadableName(i));
		}

		pAddModifierBar->LoadMenu(subMenu);

		for (int i = 0; i < modCount; ++i)
		{
			// add the className as additional data and use the human readable name here instead
			CXTPControl* menuEntry = pAddModifierBar->GetControl(i);
			menuEntry->SetDescription(pModManager->GetModifierClassName(i));
		}
	}
}

void CAnimationGraphDialog2::OnGraphAddModifier( UINT nID )
{
	// Menu Call:
	// Graph Menu-->Add Modifier-->[dynamic list of available modifier classes]
	if ( m_pGraph == NULL )
		return;

	CXTPCommandBar* pAddModifierBar = GetCommandBars()->GetMenuBar()->GetControl(2)->GetCommandBar()->GetControl(3)->GetCommandBar();

	CRY_ASSERT_MESSAGE(pAddModifierBar, "Could not retrieve Modifier Menu!");

	CXTPControl* menuEntry = pAddModifierBar->GetControl(nID - ID_GRAPH_ADDMODIFIER_FIRST);
	CString caption = menuEntry->GetDescription();
	//CString caption = menuEntry->GetCaption();
	CAG2ModifierBasePtr newMod = m_pGraph->AddNewModifier(caption);
	CRY_ASSERT_MESSAGE(newMod, "No Modifier Created!");

	m_modifierListCtrl.ReloadModifiers();
	m_modifierListCtrl.SelectItemByName(newMod->GetListDisplayString());
	m_modifierListCtrl.SetActiveWindow();
}

void CAnimationGraphDialog2::OnModifierListSelChanged( NMHDR* pNMHDR, LRESULT* pResult )
{
	*pResult = TRUE;
	if (!m_pGraph)
		return;

	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	HTREEITEM treeitem = pNMTreeView->itemNew.hItem;
	if (treeitem != NULL)
	{
		m_inputListCtrl.SelectItem(NULL);
		m_stateListCtrl.SelectItem(NULL);
		SetActiveState( NULL );
		m_vStates.clear();
		m_view->ClearSelection();
		m_previewManager.SetState(CAGState2Ptr(0));

		// set the active modifier so it's details appear
		int modifierId = m_modifierListCtrl.GetItemData(treeitem);
		m_pGraph->GetModifierManager()->SetSelectedModifier( m_pGraph->GetModifier(modifierId) );
	}
}

void CAnimationGraphDialog2::OnModifierEvent( EAG2ModifierEvent evt, CAG2ModifierBasePtr pModifier )
{
	switch (evt)
	{
	case eAG2_Modifier_Delete:
		m_modifierListCtrl.ReloadModifiers();
		//SetActiveView( m_pView );
		break;
	}
}

void CAnimationGraphDialog2::OnModifierListBeginDrag( NMHDR* pNMHDR, LRESULT* pResult )
{
	NM_TREEVIEW * pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	*pResult = TRUE;
	bool doDrag = false;

	HTREEITEM hItem = pNMTreeView->itemNew.hItem;
	m_dragModifierId = m_modifierListCtrl.GetItemData(hItem);
	CString nodeName;
	nodeName.Format("$modifier %i", m_dragModifierId);
	m_dragNodeClass = nodeName;

	doDrag = !!m_pView && m_pView->CanAddModifier( m_pGraph->GetModifier(m_dragModifierId) );

	if (doDrag)
	{
		m_pDragImage = m_stateListCtrl.CreateDragImage( hItem );
		if (m_pDragImage)
		{
			m_pDragImage->BeginDrag(0, CPoint(-10, -10));
			CRect rc;
			GetWindowRect(rc);
			CPoint p = pNMTreeView->ptDrag;
			ClientToScreen( &p );
			p.x -= rc.left;
			p.y -= rc.top;
			m_pDragImage->DragEnter( this, p );
			SetCapture();

			*pResult = FALSE;
		}
	}
}

void CAnimationGraphDialog2::OnStateNodeEvent( EHyperGraphEvent event )
{
	switch (event)
	{
	case EHG_NODE_CHANGE:
		{
			std::vector< CHyperNode* > nodes;
			m_view->GetSelectedNodes( nodes, CHyperGraphView::SELECTION_SET_ONLY_PARENTS );
			if ( nodes.size() == 1 )
			{
				SetActiveState( ((CAGNode2*)nodes[0])->GetState() );
			}
			else if ( nodes.size() > 1 )
			{
				if ( m_pView )
				{
					std::vector< CAGState2Ptr > states;
					std::vector< CHyperNode* >::iterator it, itEnd = nodes.end();
					for ( it = nodes.begin(); it != itEnd; ++it )
						if ( CAGState2* pState = ((CAGNode2*)*it)->GetState() )
							states.push_back( pState );
					SetActiveStates( states );
				}
			}
			else
			{
				SetActiveState( NULL );
				if ( m_pView && !nodes.size() )
					m_view->ClearSelection();
			}
		}
		break;
	}
}

void CAnimationGraphDialog2::OnModifierNodeEvent( CAGNodeBase2* pBaseNode, EHyperGraphEvent event )
{
	switch (event)
	{
	case EHG_NODE_CHANGE:
		{
			std::vector< CHyperNode* > nodes;
			m_view->GetSelectedNodes( nodes, CHyperGraphView::SELECTION_SET_ONLY_PARENTS );
			if ( nodes.size() == 1 )
			{
				m_pGraph->GetModifierManager()->SetSelectedModifier(((CAG2ModifierNode*) pBaseNode)->GetModifier());
			}
			else
			{
				// if nothing was selected
				SetActiveState( NULL );
				m_pGraph->GetModifierManager()->SetSelectedModifier( NULL );
				m_view->ClearSelection();
			}
			break;

		}
	}
}

void CAnimationGraphDialog2::OnInputListClick( NMHDR* pNMHDR, LRESULT* pResult )
{
	DWORD dw = GetMessagePos();
	CPoint p(GET_X_LPARAM(dw), GET_Y_LPARAM(dw));
	m_inputListCtrl.ScreenToClient(&p);

	UINT htFlags = 0;
	HTREEITEM hHitItem= m_inputListCtrl.HitTest(p, &htFlags);

	if ((hHitItem == m_inputListCtrl.GetSelectedItem()) && (htFlags & TVHT_ONITEM))
	{	
		if (hHitItem != NULL)
		{
			m_stateListCtrl.SelectItem(NULL);
			m_modifierListCtrl.SelectItem(NULL);
		}

		CString item = m_inputListCtrl.GetItemText(hHitItem);
		m_previewManager.SetState(CAGState2Ptr(0));
		m_vStates.clear();
		m_view->ClearSelection();
		m_stateEditor.EditPropertiesOf( m_pGraph->FindInput(item) );
	}
}

void CAnimationGraphDialog2::OnViewListClick( NMHDR* pNMHDR, LRESULT* pResult )
{
	DWORD dw = GetMessagePos();
	CPoint p(GET_X_LPARAM(dw), GET_Y_LPARAM(dw));
	m_viewListCtrl.ScreenToClient(&p);

	UINT htFlags = 0;
	HTREEITEM hHitItem= m_viewListCtrl.HitTest(p, &htFlags);

	if ((hHitItem == m_viewListCtrl.GetSelectedItem()) && (htFlags & TVHT_ONITEM))
	{	
		if (hHitItem != NULL)
		{
			m_stateListCtrl.SelectItem(NULL);
			m_modifierListCtrl.SelectItem(NULL);
		}

		CString item = m_viewListCtrl.GetItemText(hHitItem);
		m_previewManager.SetState(CAGState2Ptr(0));
		m_vStates.clear();
		m_view->ClearSelection();
		m_stateEditor.EditPropertiesOf( m_pGraph->FindView(item) );
	}
}

void CAnimationGraphDialog2::OnStateListClick( NMHDR* pNMHDR, LRESULT* pResult )
{
	DWORD dw = GetMessagePos();
	CPoint p(GET_X_LPARAM(dw), GET_Y_LPARAM(dw));
	m_stateListCtrl.ScreenToClient(&p);

	UINT htFlags = 0;
	HTREEITEM hHitItem= m_stateListCtrl.HitTest(p, &htFlags);

	if ((hHitItem == m_stateListCtrl.GetSelectedItem()) && (htFlags & TVHT_ONITEM))
	{	
		if (hHitItem != NULL)
		{
			m_inputListCtrl.SelectItem(NULL);
			m_modifierListCtrl.SelectItem(NULL);
		}

		CString item = m_stateListCtrl.GetItemText(hHitItem);
		m_previewManager.SetState(CAGState2Ptr(0));
		m_vStates.clear();
		m_view->ClearSelection();
		m_stateEditor.EditPropertiesOf( m_pGraph->FindState(item) );
	}
}

//////////////////////////////////////////////////////////////////////////
void CAnimationGraphDialog2::OnCustomize()
{
	CMFCUtils::ShowShortcutsCustomizeDlg(GetCommandBars(), IDR_ANIMATIONGRAPH_2, "AnimationGraph");
}

//////////////////////////////////////////////////////////////////////////
void CAnimationGraphDialog2::OnExportShortcuts()
{
	CMFCUtils::ExportShortcuts(GetCommandBars()->GetShortcutManager());
}

//////////////////////////////////////////////////////////////////////////
void CAnimationGraphDialog2::OnImportShortcuts()
{
	CMFCUtils::ImportShortcuts(GetCommandBars()->GetShortcutManager(), "AnimationGraph");
}

void CAnimationGraphDialog2::AnimationNameSelectionChanged( const CString& currentSelectedAnimationName )
{
	if(!currentSelectedAnimationName.IsEmpty())
		m_previewManager.PlayAnimation(currentSelectedAnimationName);
}
